package com.niodata.dp.api.server;

import com.niodata.dp.api.common.ApiConstants;
import com.niodata.dp.app.AppVariable;
import com.niodata.dp.app.VariableManager;
import com.niodata.dp.app.VariableValue;
import com.niodata.dp.core.resource.ResourceManager;
import com.niodata.dp.core.security.ResourceSecurityManager;
import com.niodata.dp.core.usermgr.op.GroupInfoService;
import com.niodata.dp.core.usermgr.op.UserService;
import com.niodata.dp.log.LogUtil;
import com.niodata.dp.task.ParamReference;
import com.niodata.dp.task.dao.DynamicExecutionMapper;
import com.niodata.dp.task.dao.JobMapper;
import com.niodata.dp.task.dao.PluginPackageMapper2;
import com.niodata.dp.task.entity.DynamicExecution;
import com.niodata.dp.task.entity.JobExecData;
import com.niodata.dp.task.entity.JobInfo;
import com.niodata.dp.task.entity.JobParams;
import com.niodata.dp.task.entity.JobState;
import com.niodata.dp.task.entity.PluginPackage;
import com.niodata.dp.task.entity.TaskInfo;
import com.niodata.dp.task.service.impl.AzBasedTaskManagerV2;
import com.niodata.dp.util.IdUtil;
import com.niodata.dp.util.JsonUtil;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;



@Controller
@RequestMapping("/")
@RestController
public class ApiController extends BaseController {

  private static final Logger logger = Logger.getLogger(ApiController.class);

  @Autowired
  @Qualifier("azTaskManager")
  private AzBasedTaskManagerV2 taskManager;
  @Autowired
  private JobMapper jobMapper;
  @Autowired
  private PluginPackageMapper2 pluginPackageMapper2;
  @Autowired
  private DynamicExecutionMapper executionMapper;
  @Autowired
  @Qualifier("ResourceManagerImpl")
  private ResourceManager resourceManager;
  @Autowired
  @Qualifier("DpUserMgrGroup")
  private GroupInfoService groupInfoService;
  @Autowired
  @Qualifier("DpUserMgrUser")
  private UserService userService;
  @Autowired
  @Qualifier("variableManagerImpl")
  private VariableManager variableManager;
  @Autowired
  @Qualifier("ResourceSecurityManagerImpl")
  private ResourceSecurityManager resourceSecurityManager;


  /**
   * get job config,replace all reference variable values.
   *
   * @param taskName task name
   * @param jobName  job name
   * @param execId   execid
   * @return job config
   */
  @RequestMapping(ApiConstants.URL_GET_JOB_CONF)
  @ResponseBody
  public Object getJobConfig(@RequestParam("taskName") String taskName,
                             @RequestParam("jobName") String jobName,
                             @RequestParam(value = "execId", required = true, defaultValue = "-1")
                             String execId) {

    JobInfo jobInfo = jobMapper.getJobByName(jobName, taskName);
    Map<String, Object> params = jobInfo.getParams().getParams();

    for (String key : params.keySet()) {
      if (params.get(key) == null) {
        continue;
      }
      String str = params.get(key).toString();
      ParamReference reference = ParamReference.parseFrom(str);
      if (reference == null) {
        continue;
      }
      if (reference.isApp()) {
        AppVariable variable =
            this.variableManager.getVariableByAppCode(reference.getAppCode(), reference.getVarName());
        VariableValue value = variable.getCurrentValue();
        if (value != null) {
          params.put(key, value.getValue());
        }
      } else if (reference.isInput()) {
        List<JobExecData> execDataList = this.jobMapper
            .getJobDataOfExec(Integer.parseInt(execId));
        JobExecData execData = null;
        for (JobExecData data : execDataList) {
          if (data.getJobName().equals(reference.getJobName()) && data.getParams() != null) {
            execData = data;
          }
        }
        if (execData != null) {
          params.put(key, execData.getParamValue(reference.getVarName()));
        } else {
          JobInfo jobInfo1 = jobMapper.getJobByName(reference.getJobName(), taskName);
          params.put(key, jobInfo1.getParams().getParam(reference.getVarName()));
        }
      } else if (reference.isOutput()) {
        List<JobExecData> execDataList = this.jobMapper
            .getJobDataOfExec(Integer.parseInt(execId));
        for (JobExecData execData : execDataList) {
          if (execData.getJobName().equals(reference.getJobName())) {
            params.put(key, execData.getOutParamValue(reference.getVarName()));
          }
        }
      }
    }
    try {
      logger.debug("get job params as: " + JsonUtil.toJson(params));
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
    }
    return params;
  }

  /**
   * get dynamic config by config id.
   *
   * @return job config
   */
  @RequestMapping(ApiConstants.URL_GET_DYNAMIC_CONF)
  @ResponseBody
  public Object getDynamicConfig(@RequestParam("configId") String configId) {
    logger.info("get config by config id:" + configId);
    DynamicExecution execution = executionMapper.getById(configId);
    Map<String, Object> params = execution.getParams().getParams();
    try {
      logger.debug("get job params as: " + JsonUtil.toJson(params));
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
    }
    return params;
  }

  /**
   * get plugin param schemas.
   *
   * @return paramschemas
   */
  @RequestMapping(ApiConstants.URL_GET_PARAM_SCHEMA)
  @ResponseBody
  public Object getParamSchema(@RequestParam("taskName") String taskName,
                               @RequestParam("jobName") String jobName) {
    JobInfo jobInfo = jobMapper.getJobByName(jobName, taskName);
    PluginPackage pluginPackage = pluginPackageMapper2.getPluginByPkgId(jobInfo.getPkgId());
    return pluginPackage.getParams().getParamSchemas();
  }


  /**
   * save job runtime config.
   *
   * @param taskName  task name
   * @param jobName   job name
   * @param execId    exec id
   * @param jobConfig job config
   * @return job runtime config
   * @throws IOException e
   */
  @RequestMapping(ApiConstants.URL_SAVE_JOB_RUNTIME_CONF)
  @ResponseBody
  public Object saveJobRuntimeConfig(@RequestParam("taskName") String taskName,
                                     @RequestParam("jobName") String jobName,
                                     @RequestParam("execId") String execId,
                                     @RequestBody Map<String, Object> jobConfig) throws IOException {
    JobExecData jobExecData = new JobExecData();
    JobExecData execData = this.taskManager.getJobExecData(Integer.parseInt(execId), jobName);
    boolean insert = true;
    if (execData != null) {
      insert = false;
      logger.warn("runt time config save more than one time " + execId + " " + jobName);
    }
    JobParams params = new JobParams();
    params.setParams(jobConfig);
    jobExecData.setParams(params);
    jobExecData.setExecId(execId);
    jobExecData.setJobName(jobName);
    jobExecData.setTaskName(taskName);
    TaskInfo taskInfo = taskManager.getTaskByName(taskName);
    jobExecData.setTaskId(taskInfo.getTaskId());
    List<JobInfo> jobInfos = taskManager.getJobsOfTask(taskInfo.getTaskId());
    for (JobInfo jobInfo : jobInfos) {
      if (jobInfo.getJobName().equals(jobName)) {
        jobExecData.setJobId(jobInfo.getJobId());
      }
    }
    jobExecData.setOutParams(null);
    if (insert) {
      taskManager.saveJobExecData(jobExecData);
    } else {
      taskManager.updateJobExecData(jobExecData);
    }
    logger.debug("save job config :" + JsonUtil.toJson(jobConfig));
    return "success";
  }

  @RequestMapping(ApiConstants.URL_GET_JOB_RUNTIME_CONF)
  public Object getJobRuntimeConfig(@RequestParam("taskName") String taskName,
                                    @RequestParam("jobName") String jobName, @RequestParam("execId") String execId) {
    JobExecData jobExecData = taskManager.getJobExecData(Integer.getInteger(execId), jobName);
    return jobExecData.getParams().getParams();
  }


  /**
   * save job state.
   *
   * @param taskName   taskName
   * @param jobName    jobName
   * @param scheduleId schedule id
   * @param state      map
   * @return object
   * @throws IOException IOException
   */
  @RequestMapping(ApiConstants.URL_SAVE_JOB_STATE)
  public Object saveJobState(@RequestParam("taskName") String taskName,
                             @RequestParam("jobName") String jobName,
                             @RequestParam("scheduleId") String scheduleId,
                             @RequestBody Map<String, Object> state) throws IOException {
    JobState jobState = new JobState();
    jobState.setTaskName(taskName);
    jobState.setJobName(jobName);
    jobState.setScheduleId(scheduleId);
    JobParams jobParams = new JobParams();
    jobParams.setParams(state);
    jobState.setState(jobParams);

    JobState jobState1 = this.taskManager.getJobState(taskName, jobName, scheduleId);
    if (jobState != null) {
      taskManager.updateJobState(jobState);
    } else {
      taskManager.saveJobState(jobState);
    }
    System.out.println("job state :" + JsonUtil.toJson(state));
    return "success";
  }

  @RequestMapping(ApiConstants.URL_GET_JOB_STATE)
  public Object getJobState(@RequestParam("taskName") String taskName,
                            @RequestParam("jobName") String jobName,
                            @RequestParam("scheduleId") String scheduleId) {
    JobState jobState = this.taskManager.getJobState(taskName, jobName, scheduleId);
    return jobState.getState().getParams();
  }

  @RequestMapping(ApiConstants.URL_GET_JOB_OUTPUT_PARAM)
  public Object getJobOutputParam(@RequestParam("taskName") String taskName,
                                  @RequestParam("jobName") String jobName,
                                  @RequestParam("execId") String execId) {
    JobExecData jobExecData = this.taskManager.getJobExecData(Integer.parseInt(execId), jobName);
    if (jobExecData.getOutParams() != null) {
      return jobExecData.getOutParams().getParams();
    } else {
      return Collections.emptyMap();
    }
  }

  @RequestMapping(ApiConstants.URL_GET_TASK_OUTPUT_PARAM)
  public Object getTaskOutputParam(@RequestParam("taskName") String taskName,
                                   @RequestParam("execId") String execId) {
    TaskInfo taskInfo = this.taskManager.getTaskByName(taskName);
    List<JobExecData> dataList =
        this.taskManager.getJobExecDataOfTask(taskInfo.getTaskId(), Integer.parseInt(execId));
    Map<String, Map<String, Object>> map = new HashMap<>();
    for (JobExecData data : dataList) {
      if (data.getOutParams() != null) {
        map.put(data.getJobName(), data.getOutParams().getParams());
      } else {
        map.put(data.getJobName(), Collections.EMPTY_MAP);
      }
    }
    return map;
  }

  /**
   * sava output params.
   *
   * @param params   out params
   * @param taskName task name
   * @param jobName  jobname
   * @param execId   execid
   * @return ok
   * @throws IOException ioe
   */
  @RequestMapping(ApiConstants.URL_SAVE_JOB_OUTPUT_PARAM)
  public Object saveJobOutputParam(@RequestBody Map<String, Object> params,
                                   @RequestParam("taskName") String taskName,
                                   @RequestParam("jobName") String jobName,
                                   @RequestParam("execId") String execId) throws IOException {
    JobExecData jobExecData = this.taskManager.getJobExecData(Integer.parseInt(execId), jobName);
    boolean insert = false;
    if (jobExecData == null) {
      jobExecData = new JobExecData();
      jobExecData.setTaskName(taskName);
      jobExecData.setJobName(jobName);
      jobExecData.setExecId(execId);
      TaskInfo taskInfo = taskManager.getTaskByName(taskName);
      List<JobInfo> jobInfos = taskManager.getJobsOfTask(taskInfo.getTaskId());
      for (JobInfo jobInfo : jobInfos) {
        if (jobInfo.getJobName().equals(jobName)) {
          jobExecData.setJobId(jobInfo.getJobId());
          break;
        }
      }
      jobExecData.setTaskId(taskInfo.getTaskId());
      insert = true;
    }
    JobParams jobParams = new JobParams();
    jobParams.setParams(params);
    jobExecData.setOutParams(jobParams);
    if (insert) {
      taskManager.saveJobExecData(jobExecData);
    } else {
      taskManager.updateJobExecData(jobExecData);
    }
    variableManager.applyUpdate(taskName, jobName, params);
    logger.debug("save job output param success:" + JsonUtil.toJson(params));
    return "success";
  }
}
